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