root/drivers/clk/at91/pmc.c

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

DEFINITIONS

This source file includes following definitions.
  1. of_at91_get_clk_range
  2. of_clk_hw_pmc_get
  3. pmc_data_free
  4. pmc_data_allocate
  5. pmc_register_id
  6. pmc_register_pck
  7. pmc_suspend
  8. pmc_ready
  9. pmc_resume
  10. pmc_register_ops

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
   4  */
   5 
   6 #include <linux/clk-provider.h>
   7 #include <linux/clkdev.h>
   8 #include <linux/clk/at91_pmc.h>
   9 #include <linux/of.h>
  10 #include <linux/mfd/syscon.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/regmap.h>
  13 #include <linux/syscore_ops.h>
  14 
  15 #include <asm/proc-fns.h>
  16 
  17 #include <dt-bindings/clock/at91.h>
  18 
  19 #include "pmc.h"
  20 
  21 #define PMC_MAX_IDS 128
  22 #define PMC_MAX_PCKS 8
  23 
  24 int of_at91_get_clk_range(struct device_node *np, const char *propname,
  25                           struct clk_range *range)
  26 {
  27         u32 min, max;
  28         int ret;
  29 
  30         ret = of_property_read_u32_index(np, propname, 0, &min);
  31         if (ret)
  32                 return ret;
  33 
  34         ret = of_property_read_u32_index(np, propname, 1, &max);
  35         if (ret)
  36                 return ret;
  37 
  38         if (range) {
  39                 range->min = min;
  40                 range->max = max;
  41         }
  42 
  43         return 0;
  44 }
  45 EXPORT_SYMBOL_GPL(of_at91_get_clk_range);
  46 
  47 struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data)
  48 {
  49         unsigned int type = clkspec->args[0];
  50         unsigned int idx = clkspec->args[1];
  51         struct pmc_data *pmc_data = data;
  52 
  53         switch (type) {
  54         case PMC_TYPE_CORE:
  55                 if (idx < pmc_data->ncore)
  56                         return pmc_data->chws[idx];
  57                 break;
  58         case PMC_TYPE_SYSTEM:
  59                 if (idx < pmc_data->nsystem)
  60                         return pmc_data->shws[idx];
  61                 break;
  62         case PMC_TYPE_PERIPHERAL:
  63                 if (idx < pmc_data->nperiph)
  64                         return pmc_data->phws[idx];
  65                 break;
  66         case PMC_TYPE_GCK:
  67                 if (idx < pmc_data->ngck)
  68                         return pmc_data->ghws[idx];
  69                 break;
  70         default:
  71                 break;
  72         }
  73 
  74         pr_err("%s: invalid type (%u) or index (%u)\n", __func__, type, idx);
  75 
  76         return ERR_PTR(-EINVAL);
  77 }
  78 
  79 void pmc_data_free(struct pmc_data *pmc_data)
  80 {
  81         kfree(pmc_data->chws);
  82         kfree(pmc_data->shws);
  83         kfree(pmc_data->phws);
  84         kfree(pmc_data->ghws);
  85 }
  86 
  87 struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
  88                                    unsigned int nperiph, unsigned int ngck)
  89 {
  90         struct pmc_data *pmc_data = kzalloc(sizeof(*pmc_data), GFP_KERNEL);
  91 
  92         if (!pmc_data)
  93                 return NULL;
  94 
  95         pmc_data->ncore = ncore;
  96         pmc_data->chws = kcalloc(ncore, sizeof(struct clk_hw *), GFP_KERNEL);
  97         if (!pmc_data->chws)
  98                 goto err;
  99 
 100         pmc_data->nsystem = nsystem;
 101         pmc_data->shws = kcalloc(nsystem, sizeof(struct clk_hw *), GFP_KERNEL);
 102         if (!pmc_data->shws)
 103                 goto err;
 104 
 105         pmc_data->nperiph = nperiph;
 106         pmc_data->phws = kcalloc(nperiph, sizeof(struct clk_hw *), GFP_KERNEL);
 107         if (!pmc_data->phws)
 108                 goto err;
 109 
 110         pmc_data->ngck = ngck;
 111         pmc_data->ghws = kcalloc(ngck, sizeof(struct clk_hw *), GFP_KERNEL);
 112         if (!pmc_data->ghws)
 113                 goto err;
 114 
 115         return pmc_data;
 116 
 117 err:
 118         pmc_data_free(pmc_data);
 119 
 120         return NULL;
 121 }
 122 
 123 #ifdef CONFIG_PM
 124 static struct regmap *pmcreg;
 125 
 126 static u8 registered_ids[PMC_MAX_IDS];
 127 static u8 registered_pcks[PMC_MAX_PCKS];
 128 
 129 static struct
 130 {
 131         u32 scsr;
 132         u32 pcsr0;
 133         u32 uckr;
 134         u32 mor;
 135         u32 mcfr;
 136         u32 pllar;
 137         u32 mckr;
 138         u32 usb;
 139         u32 imr;
 140         u32 pcsr1;
 141         u32 pcr[PMC_MAX_IDS];
 142         u32 audio_pll0;
 143         u32 audio_pll1;
 144         u32 pckr[PMC_MAX_PCKS];
 145 } pmc_cache;
 146 
 147 /*
 148  * As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored
 149  * without alteration in the table, and 0 is for unused clocks.
 150  */
 151 void pmc_register_id(u8 id)
 152 {
 153         int i;
 154 
 155         for (i = 0; i < PMC_MAX_IDS; i++) {
 156                 if (registered_ids[i] == 0) {
 157                         registered_ids[i] = id;
 158                         break;
 159                 }
 160                 if (registered_ids[i] == id)
 161                         break;
 162         }
 163 }
 164 
 165 /*
 166  * As Programmable Clock 0 is valid on AT91 chips, there is an offset
 167  * of 1 between the stored value and the real clock ID.
 168  */
 169 void pmc_register_pck(u8 pck)
 170 {
 171         int i;
 172 
 173         for (i = 0; i < PMC_MAX_PCKS; i++) {
 174                 if (registered_pcks[i] == 0) {
 175                         registered_pcks[i] = pck + 1;
 176                         break;
 177                 }
 178                 if (registered_pcks[i] == (pck + 1))
 179                         break;
 180         }
 181 }
 182 
 183 static int pmc_suspend(void)
 184 {
 185         int i;
 186         u8 num;
 187 
 188         regmap_read(pmcreg, AT91_PMC_SCSR, &pmc_cache.scsr);
 189         regmap_read(pmcreg, AT91_PMC_PCSR, &pmc_cache.pcsr0);
 190         regmap_read(pmcreg, AT91_CKGR_UCKR, &pmc_cache.uckr);
 191         regmap_read(pmcreg, AT91_CKGR_MOR, &pmc_cache.mor);
 192         regmap_read(pmcreg, AT91_CKGR_MCFR, &pmc_cache.mcfr);
 193         regmap_read(pmcreg, AT91_CKGR_PLLAR, &pmc_cache.pllar);
 194         regmap_read(pmcreg, AT91_PMC_MCKR, &pmc_cache.mckr);
 195         regmap_read(pmcreg, AT91_PMC_USB, &pmc_cache.usb);
 196         regmap_read(pmcreg, AT91_PMC_IMR, &pmc_cache.imr);
 197         regmap_read(pmcreg, AT91_PMC_PCSR1, &pmc_cache.pcsr1);
 198 
 199         for (i = 0; registered_ids[i]; i++) {
 200                 regmap_write(pmcreg, AT91_PMC_PCR,
 201                              (registered_ids[i] & AT91_PMC_PCR_PID_MASK));
 202                 regmap_read(pmcreg, AT91_PMC_PCR,
 203                             &pmc_cache.pcr[registered_ids[i]]);
 204         }
 205         for (i = 0; registered_pcks[i]; i++) {
 206                 num = registered_pcks[i] - 1;
 207                 regmap_read(pmcreg, AT91_PMC_PCKR(num), &pmc_cache.pckr[num]);
 208         }
 209 
 210         return 0;
 211 }
 212 
 213 static bool pmc_ready(unsigned int mask)
 214 {
 215         unsigned int status;
 216 
 217         regmap_read(pmcreg, AT91_PMC_SR, &status);
 218 
 219         return ((status & mask) == mask) ? 1 : 0;
 220 }
 221 
 222 static void pmc_resume(void)
 223 {
 224         int i;
 225         u8 num;
 226         u32 tmp;
 227         u32 mask = AT91_PMC_MCKRDY | AT91_PMC_LOCKA;
 228 
 229         regmap_read(pmcreg, AT91_PMC_MCKR, &tmp);
 230         if (pmc_cache.mckr != tmp)
 231                 pr_warn("MCKR was not configured properly by the firmware\n");
 232         regmap_read(pmcreg, AT91_CKGR_PLLAR, &tmp);
 233         if (pmc_cache.pllar != tmp)
 234                 pr_warn("PLLAR was not configured properly by the firmware\n");
 235 
 236         regmap_write(pmcreg, AT91_PMC_SCER, pmc_cache.scsr);
 237         regmap_write(pmcreg, AT91_PMC_PCER, pmc_cache.pcsr0);
 238         regmap_write(pmcreg, AT91_CKGR_UCKR, pmc_cache.uckr);
 239         regmap_write(pmcreg, AT91_CKGR_MOR, pmc_cache.mor);
 240         regmap_write(pmcreg, AT91_CKGR_MCFR, pmc_cache.mcfr);
 241         regmap_write(pmcreg, AT91_PMC_USB, pmc_cache.usb);
 242         regmap_write(pmcreg, AT91_PMC_IMR, pmc_cache.imr);
 243         regmap_write(pmcreg, AT91_PMC_PCER1, pmc_cache.pcsr1);
 244 
 245         for (i = 0; registered_ids[i]; i++) {
 246                 regmap_write(pmcreg, AT91_PMC_PCR,
 247                              pmc_cache.pcr[registered_ids[i]] |
 248                              AT91_PMC_PCR_CMD);
 249         }
 250         for (i = 0; registered_pcks[i]; i++) {
 251                 num = registered_pcks[i] - 1;
 252                 regmap_write(pmcreg, AT91_PMC_PCKR(num), pmc_cache.pckr[num]);
 253         }
 254 
 255         if (pmc_cache.uckr & AT91_PMC_UPLLEN)
 256                 mask |= AT91_PMC_LOCKU;
 257 
 258         while (!pmc_ready(mask))
 259                 cpu_relax();
 260 }
 261 
 262 static struct syscore_ops pmc_syscore_ops = {
 263         .suspend = pmc_suspend,
 264         .resume = pmc_resume,
 265 };
 266 
 267 static const struct of_device_id sama5d2_pmc_dt_ids[] = {
 268         { .compatible = "atmel,sama5d2-pmc" },
 269         { /* sentinel */ }
 270 };
 271 
 272 static int __init pmc_register_ops(void)
 273 {
 274         struct device_node *np;
 275 
 276         np = of_find_matching_node(NULL, sama5d2_pmc_dt_ids);
 277 
 278         pmcreg = device_node_to_regmap(np);
 279         if (IS_ERR(pmcreg))
 280                 return PTR_ERR(pmcreg);
 281 
 282         register_syscore_ops(&pmc_syscore_ops);
 283 
 284         return 0;
 285 }
 286 /* This has to happen before arch_initcall because of the tcb_clksrc driver */
 287 postcore_initcall(pmc_register_ops);
 288 #endif

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