1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
7 #include <linux/clk-provider.h>
8 #include <linux/clkdev.h>
9 #include <linux/clk/at91_pmc.h>
11 #include <linux/of_address.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/platform_device.h>
14 #include <linux/regmap.h>
15 #include <linux/syscore_ops.h>
17 #include <asm/proc-fns.h>
21 #define PMC_MAX_IDS 128
22 #define PMC_MAX_PCKS 8
24 int of_at91_get_clk_range(struct device_node
*np
, const char *propname
,
25 struct clk_range
*range
)
30 ret
= of_property_read_u32_index(np
, propname
, 0, &min
);
34 ret
= of_property_read_u32_index(np
, propname
, 1, &max
);
45 EXPORT_SYMBOL_GPL(of_at91_get_clk_range
);
47 struct clk_hw
*of_clk_hw_pmc_get(struct of_phandle_args
*clkspec
, void *data
)
49 unsigned int type
= clkspec
->args
[0];
50 unsigned int idx
= clkspec
->args
[1];
51 struct pmc_data
*pmc_data
= data
;
55 if (idx
< pmc_data
->ncore
)
56 return pmc_data
->chws
[idx
];
59 if (idx
< pmc_data
->nsystem
)
60 return pmc_data
->shws
[idx
];
62 case PMC_TYPE_PERIPHERAL
:
63 if (idx
< pmc_data
->nperiph
)
64 return pmc_data
->phws
[idx
];
67 if (idx
< pmc_data
->ngck
)
68 return pmc_data
->ghws
[idx
];
70 case PMC_TYPE_PROGRAMMABLE
:
71 if (idx
< pmc_data
->npck
)
72 return pmc_data
->pchws
[idx
];
78 pr_err("%s: invalid type (%u) or index (%u)\n", __func__
, type
, idx
);
80 return ERR_PTR(-EINVAL
);
83 struct pmc_data
*pmc_data_allocate(unsigned int ncore
, unsigned int nsystem
,
84 unsigned int nperiph
, unsigned int ngck
,
87 unsigned int num_clks
= ncore
+ nsystem
+ nperiph
+ ngck
+ npck
;
88 struct pmc_data
*pmc_data
;
90 pmc_data
= kzalloc(struct_size(pmc_data
, hwtable
, num_clks
),
95 pmc_data
->ncore
= ncore
;
96 pmc_data
->chws
= pmc_data
->hwtable
;
98 pmc_data
->nsystem
= nsystem
;
99 pmc_data
->shws
= pmc_data
->chws
+ ncore
;
101 pmc_data
->nperiph
= nperiph
;
102 pmc_data
->phws
= pmc_data
->shws
+ nsystem
;
104 pmc_data
->ngck
= ngck
;
105 pmc_data
->ghws
= pmc_data
->phws
+ nperiph
;
107 pmc_data
->npck
= npck
;
108 pmc_data
->pchws
= pmc_data
->ghws
+ ngck
;
115 /* Address in SECURAM that say if we suspend to backup mode. */
116 static void __iomem
*at91_pmc_backup_suspend
;
118 static int at91_pmc_suspend(void)
122 if (!at91_pmc_backup_suspend
)
125 backup
= readl_relaxed(at91_pmc_backup_suspend
);
129 return clk_save_context();
132 static void at91_pmc_resume(void)
136 if (!at91_pmc_backup_suspend
)
139 backup
= readl_relaxed(at91_pmc_backup_suspend
);
143 clk_restore_context();
146 static struct syscore_ops pmc_syscore_ops
= {
147 .suspend
= at91_pmc_suspend
,
148 .resume
= at91_pmc_resume
,
151 static const struct of_device_id pmc_dt_ids
[] = {
152 { .compatible
= "atmel,sama5d2-pmc" },
153 { .compatible
= "microchip,sama7g5-pmc", },
157 static int __init
pmc_register_ops(void)
159 struct device_node
*np
;
161 np
= of_find_matching_node(NULL
, pmc_dt_ids
);
165 if (!of_device_is_available(np
)) {
171 np
= of_find_compatible_node(NULL
, NULL
, "atmel,sama5d2-securam");
175 if (!of_device_is_available(np
)) {
181 at91_pmc_backup_suspend
= of_iomap(np
, 0);
182 if (!at91_pmc_backup_suspend
) {
183 pr_warn("%s(): unable to map securam\n", __func__
);
187 register_syscore_ops(&pmc_syscore_ops
);
191 /* This has to happen before arch_initcall because of the tcb_clksrc driver */
192 postcore_initcall(pmc_register_ops
);