root/drivers/clk/nxp/clk-lpc18xx-creg.c

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

DEFINITIONS

This source file includes following definitions.
  1. clk_creg_32k_prepare
  2. clk_creg_32k_unprepare
  3. clk_creg_32k_is_prepared
  4. clk_creg_1k_recalc_rate
  5. clk_creg_enable
  6. clk_creg_disable
  7. clk_creg_is_enabled
  8. clk_register_creg_clk
  9. lpc18xx_creg_clk_init
  10. lpc18xx_creg_clk_probe

   1 /*
   2  * Clk driver for NXP LPC18xx/43xx Configuration Registers (CREG)
   3  *
   4  * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
   5  *
   6  * This file is licensed under the terms of the GNU General Public
   7  * License version 2. This program is licensed "as is" without any
   8  * warranty of any kind, whether express or implied.
   9  */
  10 
  11 #include <linux/clk-provider.h>
  12 #include <linux/delay.h>
  13 #include <linux/kernel.h>
  14 #include <linux/mfd/syscon.h>
  15 #include <linux/of.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/regmap.h>
  18 
  19 #define LPC18XX_CREG_CREG0                      0x004
  20 #define  LPC18XX_CREG_CREG0_EN1KHZ              BIT(0)
  21 #define  LPC18XX_CREG_CREG0_EN32KHZ             BIT(1)
  22 #define  LPC18XX_CREG_CREG0_RESET32KHZ          BIT(2)
  23 #define  LPC18XX_CREG_CREG0_PD32KHZ             BIT(3)
  24 
  25 #define to_clk_creg(_hw) container_of(_hw, struct clk_creg_data, hw)
  26 
  27 enum {
  28         CREG_CLK_1KHZ,
  29         CREG_CLK_32KHZ,
  30         CREG_CLK_MAX,
  31 };
  32 
  33 struct clk_creg_data {
  34         struct clk_hw hw;
  35         const char *name;
  36         struct regmap *reg;
  37         unsigned int en_mask;
  38         const struct clk_ops *ops;
  39 };
  40 
  41 #define CREG_CLK(_name, _emask, _ops)           \
  42 {                                               \
  43         .name = _name,                          \
  44         .en_mask = LPC18XX_CREG_CREG0_##_emask, \
  45         .ops = &_ops,                           \
  46 }
  47 
  48 static int clk_creg_32k_prepare(struct clk_hw *hw)
  49 {
  50         struct clk_creg_data *creg = to_clk_creg(hw);
  51         int ret;
  52 
  53         ret = regmap_update_bits(creg->reg, LPC18XX_CREG_CREG0,
  54                                  LPC18XX_CREG_CREG0_PD32KHZ |
  55                                  LPC18XX_CREG_CREG0_RESET32KHZ, 0);
  56 
  57         /*
  58          * Powering up the 32k oscillator takes a long while
  59          * and sadly there aren't any status bit to poll.
  60          */
  61         msleep(2500);
  62 
  63         return ret;
  64 }
  65 
  66 static void clk_creg_32k_unprepare(struct clk_hw *hw)
  67 {
  68         struct clk_creg_data *creg = to_clk_creg(hw);
  69 
  70         regmap_update_bits(creg->reg, LPC18XX_CREG_CREG0,
  71                            LPC18XX_CREG_CREG0_PD32KHZ,
  72                            LPC18XX_CREG_CREG0_PD32KHZ);
  73 }
  74 
  75 static int clk_creg_32k_is_prepared(struct clk_hw *hw)
  76 {
  77         struct clk_creg_data *creg = to_clk_creg(hw);
  78         u32 reg;
  79 
  80         regmap_read(creg->reg, LPC18XX_CREG_CREG0, &reg);
  81 
  82         return !(reg & LPC18XX_CREG_CREG0_PD32KHZ) &&
  83                !(reg & LPC18XX_CREG_CREG0_RESET32KHZ);
  84 }
  85 
  86 static unsigned long clk_creg_1k_recalc_rate(struct clk_hw *hw,
  87                                              unsigned long parent_rate)
  88 {
  89         return parent_rate / 32;
  90 }
  91 
  92 static int clk_creg_enable(struct clk_hw *hw)
  93 {
  94         struct clk_creg_data *creg = to_clk_creg(hw);
  95 
  96         return regmap_update_bits(creg->reg, LPC18XX_CREG_CREG0,
  97                                   creg->en_mask, creg->en_mask);
  98 }
  99 
 100 static void clk_creg_disable(struct clk_hw *hw)
 101 {
 102         struct clk_creg_data *creg = to_clk_creg(hw);
 103 
 104         regmap_update_bits(creg->reg, LPC18XX_CREG_CREG0,
 105                            creg->en_mask, 0);
 106 }
 107 
 108 static int clk_creg_is_enabled(struct clk_hw *hw)
 109 {
 110         struct clk_creg_data *creg = to_clk_creg(hw);
 111         u32 reg;
 112 
 113         regmap_read(creg->reg, LPC18XX_CREG_CREG0, &reg);
 114 
 115         return !!(reg & creg->en_mask);
 116 }
 117 
 118 static const struct clk_ops clk_creg_32k = {
 119         .enable         = clk_creg_enable,
 120         .disable        = clk_creg_disable,
 121         .is_enabled     = clk_creg_is_enabled,
 122         .prepare        = clk_creg_32k_prepare,
 123         .unprepare      = clk_creg_32k_unprepare,
 124         .is_prepared    = clk_creg_32k_is_prepared,
 125 };
 126 
 127 static const struct clk_ops clk_creg_1k = {
 128         .enable         = clk_creg_enable,
 129         .disable        = clk_creg_disable,
 130         .is_enabled     = clk_creg_is_enabled,
 131         .recalc_rate    = clk_creg_1k_recalc_rate,
 132 };
 133 
 134 static struct clk_creg_data clk_creg_clocks[] = {
 135         [CREG_CLK_1KHZ]  = CREG_CLK("1khz_clk",  EN1KHZ,  clk_creg_1k),
 136         [CREG_CLK_32KHZ] = CREG_CLK("32khz_clk", EN32KHZ, clk_creg_32k),
 137 };
 138 
 139 static struct clk *clk_register_creg_clk(struct device *dev,
 140                                          struct clk_creg_data *creg_clk,
 141                                          const char **parent_name,
 142                                          struct regmap *syscon)
 143 {
 144         struct clk_init_data init;
 145 
 146         init.ops = creg_clk->ops;
 147         init.name = creg_clk->name;
 148         init.parent_names = parent_name;
 149         init.num_parents = 1;
 150         init.flags = 0;
 151 
 152         creg_clk->reg = syscon;
 153         creg_clk->hw.init = &init;
 154 
 155         if (dev)
 156                 return devm_clk_register(dev, &creg_clk->hw);
 157 
 158         return clk_register(NULL, &creg_clk->hw);
 159 }
 160 
 161 static struct clk *clk_creg_early[CREG_CLK_MAX];
 162 static struct clk_onecell_data clk_creg_early_data = {
 163         .clks = clk_creg_early,
 164         .clk_num = CREG_CLK_MAX,
 165 };
 166 
 167 static void __init lpc18xx_creg_clk_init(struct device_node *np)
 168 {
 169         const char *clk_32khz_parent;
 170         struct regmap *syscon;
 171 
 172         syscon = syscon_node_to_regmap(np->parent);
 173         if (IS_ERR(syscon)) {
 174                 pr_err("%s: syscon lookup failed\n", __func__);
 175                 return;
 176         }
 177 
 178         clk_32khz_parent = of_clk_get_parent_name(np, 0);
 179 
 180         clk_creg_early[CREG_CLK_32KHZ] =
 181                 clk_register_creg_clk(NULL, &clk_creg_clocks[CREG_CLK_32KHZ],
 182                                       &clk_32khz_parent, syscon);
 183         clk_creg_early[CREG_CLK_1KHZ] = ERR_PTR(-EPROBE_DEFER);
 184 
 185         of_clk_add_provider(np, of_clk_src_onecell_get, &clk_creg_early_data);
 186 }
 187 CLK_OF_DECLARE_DRIVER(lpc18xx_creg_clk, "nxp,lpc1850-creg-clk",
 188                       lpc18xx_creg_clk_init);
 189 
 190 static struct clk *clk_creg[CREG_CLK_MAX];
 191 static struct clk_onecell_data clk_creg_data = {
 192         .clks = clk_creg,
 193         .clk_num = CREG_CLK_MAX,
 194 };
 195 
 196 static int lpc18xx_creg_clk_probe(struct platform_device *pdev)
 197 {
 198         struct device_node *np = pdev->dev.of_node;
 199         struct regmap *syscon;
 200 
 201         syscon = syscon_node_to_regmap(np->parent);
 202         if (IS_ERR(syscon)) {
 203                 dev_err(&pdev->dev, "syscon lookup failed\n");
 204                 return PTR_ERR(syscon);
 205         }
 206 
 207         clk_creg[CREG_CLK_32KHZ] = clk_creg_early[CREG_CLK_32KHZ];
 208         clk_creg[CREG_CLK_1KHZ] =
 209                 clk_register_creg_clk(NULL, &clk_creg_clocks[CREG_CLK_1KHZ],
 210                                       &clk_creg_clocks[CREG_CLK_32KHZ].name,
 211                                       syscon);
 212 
 213         return of_clk_add_provider(np, of_clk_src_onecell_get, &clk_creg_data);
 214 }
 215 
 216 static const struct of_device_id lpc18xx_creg_clk_of_match[] = {
 217         { .compatible = "nxp,lpc1850-creg-clk" },
 218         {},
 219 };
 220 
 221 static struct platform_driver lpc18xx_creg_clk_driver = {
 222         .probe = lpc18xx_creg_clk_probe,
 223         .driver = {
 224                 .name = "lpc18xx-creg-clk",
 225                 .of_match_table = lpc18xx_creg_clk_of_match,
 226         },
 227 };
 228 builtin_platform_driver(lpc18xx_creg_clk_driver);

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