Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/clk-provider.h>
0008 #include <linux/clkdev.h>
0009 #include <linux/clk/at91_pmc.h>
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/regmap.h>
0015 #include <linux/syscore_ops.h>
0016 
0017 #include <asm/proc-fns.h>
0018 
0019 #include "pmc.h"
0020 
0021 #define PMC_MAX_IDS 128
0022 #define PMC_MAX_PCKS 8
0023 
0024 int of_at91_get_clk_range(struct device_node *np, const char *propname,
0025               struct clk_range *range)
0026 {
0027     u32 min, max;
0028     int ret;
0029 
0030     ret = of_property_read_u32_index(np, propname, 0, &min);
0031     if (ret)
0032         return ret;
0033 
0034     ret = of_property_read_u32_index(np, propname, 1, &max);
0035     if (ret)
0036         return ret;
0037 
0038     if (range) {
0039         range->min = min;
0040         range->max = max;
0041     }
0042 
0043     return 0;
0044 }
0045 EXPORT_SYMBOL_GPL(of_at91_get_clk_range);
0046 
0047 struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data)
0048 {
0049     unsigned int type = clkspec->args[0];
0050     unsigned int idx = clkspec->args[1];
0051     struct pmc_data *pmc_data = data;
0052 
0053     switch (type) {
0054     case PMC_TYPE_CORE:
0055         if (idx < pmc_data->ncore)
0056             return pmc_data->chws[idx];
0057         break;
0058     case PMC_TYPE_SYSTEM:
0059         if (idx < pmc_data->nsystem)
0060             return pmc_data->shws[idx];
0061         break;
0062     case PMC_TYPE_PERIPHERAL:
0063         if (idx < pmc_data->nperiph)
0064             return pmc_data->phws[idx];
0065         break;
0066     case PMC_TYPE_GCK:
0067         if (idx < pmc_data->ngck)
0068             return pmc_data->ghws[idx];
0069         break;
0070     case PMC_TYPE_PROGRAMMABLE:
0071         if (idx < pmc_data->npck)
0072             return pmc_data->pchws[idx];
0073         break;
0074     default:
0075         break;
0076     }
0077 
0078     pr_err("%s: invalid type (%u) or index (%u)\n", __func__, type, idx);
0079 
0080     return ERR_PTR(-EINVAL);
0081 }
0082 
0083 struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
0084                    unsigned int nperiph, unsigned int ngck,
0085                    unsigned int npck)
0086 {
0087     unsigned int num_clks = ncore + nsystem + nperiph + ngck + npck;
0088     struct pmc_data *pmc_data;
0089 
0090     pmc_data = kzalloc(struct_size(pmc_data, hwtable, num_clks),
0091                GFP_KERNEL);
0092     if (!pmc_data)
0093         return NULL;
0094 
0095     pmc_data->ncore = ncore;
0096     pmc_data->chws = pmc_data->hwtable;
0097 
0098     pmc_data->nsystem = nsystem;
0099     pmc_data->shws = pmc_data->chws + ncore;
0100 
0101     pmc_data->nperiph = nperiph;
0102     pmc_data->phws = pmc_data->shws + nsystem;
0103 
0104     pmc_data->ngck = ngck;
0105     pmc_data->ghws = pmc_data->phws + nperiph;
0106 
0107     pmc_data->npck = npck;
0108     pmc_data->pchws = pmc_data->ghws + ngck;
0109 
0110     return pmc_data;
0111 }
0112 
0113 #ifdef CONFIG_PM
0114 
0115 /* Address in SECURAM that say if we suspend to backup mode. */
0116 static void __iomem *at91_pmc_backup_suspend;
0117 
0118 static int at91_pmc_suspend(void)
0119 {
0120     unsigned int backup;
0121 
0122     if (!at91_pmc_backup_suspend)
0123         return 0;
0124 
0125     backup = readl_relaxed(at91_pmc_backup_suspend);
0126     if (!backup)
0127         return 0;
0128 
0129     return clk_save_context();
0130 }
0131 
0132 static void at91_pmc_resume(void)
0133 {
0134     unsigned int backup;
0135 
0136     if (!at91_pmc_backup_suspend)
0137         return;
0138 
0139     backup = readl_relaxed(at91_pmc_backup_suspend);
0140     if (!backup)
0141         return;
0142 
0143     clk_restore_context();
0144 }
0145 
0146 static struct syscore_ops pmc_syscore_ops = {
0147     .suspend = at91_pmc_suspend,
0148     .resume = at91_pmc_resume,
0149 };
0150 
0151 static const struct of_device_id pmc_dt_ids[] = {
0152     { .compatible = "atmel,sama5d2-pmc" },
0153     { .compatible = "microchip,sama7g5-pmc", },
0154     { /* sentinel */ }
0155 };
0156 
0157 static int __init pmc_register_ops(void)
0158 {
0159     struct device_node *np;
0160 
0161     np = of_find_matching_node(NULL, pmc_dt_ids);
0162     if (!np)
0163         return -ENODEV;
0164 
0165     if (!of_device_is_available(np)) {
0166         of_node_put(np);
0167         return -ENODEV;
0168     }
0169     of_node_put(np);
0170 
0171     np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-securam");
0172     if (!np)
0173         return -ENODEV;
0174 
0175     if (!of_device_is_available(np)) {
0176         of_node_put(np);
0177         return -ENODEV;
0178     }
0179     of_node_put(np);
0180 
0181     at91_pmc_backup_suspend = of_iomap(np, 0);
0182     if (!at91_pmc_backup_suspend) {
0183         pr_warn("%s(): unable to map securam\n", __func__);
0184         return -ENOMEM;
0185     }
0186 
0187     register_syscore_ops(&pmc_syscore_ops);
0188 
0189     return 0;
0190 }
0191 /* This has to happen before arch_initcall because of the tcb_clksrc driver */
0192 postcore_initcall(pmc_register_ops);
0193 #endif