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