1 // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause
2 /*
3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4 * Copyright (C) 2021 Microchip
5 */
6
7 #include <io.h>
8 #include <kernel/delay.h>
9 #include <kernel/panic.h>
10 #include <mm/core_memprot.h>
11 #include <types_ext.h>
12
13 #include "at91_clk.h"
14
clk_plldiv_get_rate(struct clk * clk,unsigned long parent_rate)15 static unsigned long clk_plldiv_get_rate(struct clk *clk,
16 unsigned long parent_rate)
17 {
18 struct pmc_data *pmc = clk->priv;
19 unsigned int mckr = io_read32(pmc->base + AT91_PMC_MCKR);
20
21 if (mckr & AT91_PMC_PLLADIV2)
22 return parent_rate / 2;
23
24 return parent_rate;
25 }
26
clk_plldiv_set_rate(struct clk * clk,unsigned long rate,unsigned long parent_rate)27 static TEE_Result clk_plldiv_set_rate(struct clk *clk, unsigned long rate,
28 unsigned long parent_rate)
29 {
30 struct pmc_data *pmc = clk->priv;
31
32 if (parent_rate != rate && (parent_rate / 2 != rate))
33 return TEE_ERROR_GENERIC;
34
35 io_clrsetbits32(pmc->base + AT91_PMC_MCKR, AT91_PMC_PLLADIV2,
36 parent_rate != rate ? AT91_PMC_PLLADIV2 : 0);
37
38 return TEE_SUCCESS;
39 }
40
41 static const struct clk_ops plldiv_ops = {
42 .get_rate = clk_plldiv_get_rate,
43 .set_rate = clk_plldiv_set_rate,
44 };
45
46 struct clk *
at91_clk_register_plldiv(struct pmc_data * pmc,const char * name,struct clk * parent)47 at91_clk_register_plldiv(struct pmc_data *pmc, const char *name,
48 struct clk *parent)
49 {
50 struct clk *clk = NULL;
51
52 clk = clk_alloc(name, &plldiv_ops, &parent, 1);
53 if (!clk)
54 return NULL;
55
56 clk->priv = pmc;
57 clk->flags = CLK_SET_RATE_GATE;
58
59 if (clk_register(clk)) {
60 clk_free(clk);
61 return NULL;
62 }
63
64 return clk;
65 }
66