1 // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause 2 /* 3 * Copyright (C) 2014 Atmel 4 * 5 * Alexandre Belloni <alexandre.belloni@free-electrons.com> 6 */ 7 8 #include <io.h> 9 #include <kernel/delay.h> 10 #include <mm/core_memprot.h> 11 #include <types_ext.h> 12 13 #include "at91_clk.h" 14 15 #define H32MX_MAX_FREQ 90000000 16 17 static unsigned long clk_sama5d4_h32mx_get_rate(struct clk *clk, 18 unsigned long parent_rate) 19 { 20 struct pmc_data *pmc = clk->priv; 21 unsigned int mckr = io_read32(pmc->base + AT91_PMC_MCKR); 22 23 if (mckr & AT91_PMC_H32MXDIV) 24 return parent_rate / 2; 25 26 if (parent_rate > H32MX_MAX_FREQ) 27 IMSG("H32MX clock is too fast"); 28 29 return parent_rate; 30 } 31 32 static TEE_Result clk_sama5d4_h32mx_set_rate(struct clk *clk, 33 unsigned long rate, 34 unsigned long parent_rate) 35 { 36 struct pmc_data *pmc = clk->priv; 37 uint32_t mckr = 0; 38 39 if (parent_rate != rate && (parent_rate / 2) != rate) 40 return TEE_ERROR_BAD_PARAMETERS; 41 42 if ((parent_rate / 2) == rate) 43 mckr = AT91_PMC_H32MXDIV; 44 45 io_clrsetbits32(pmc->base + AT91_PMC_MCKR, AT91_PMC_H32MXDIV, mckr); 46 47 return TEE_SUCCESS; 48 } 49 50 static const struct clk_ops h32mx_ops = { 51 .get_rate = clk_sama5d4_h32mx_get_rate, 52 .set_rate = clk_sama5d4_h32mx_set_rate, 53 }; 54 55 struct clk * 56 at91_clk_register_h32mx(struct pmc_data *pmc, const char *name, 57 struct clk *parent) 58 { 59 struct clk *clk = NULL; 60 61 clk = clk_alloc(name, &h32mx_ops, &parent, 1); 62 if (!clk) 63 return NULL; 64 65 clk->ops = &h32mx_ops; 66 clk->priv = pmc; 67 clk->name = name; 68 clk->flags = CLK_SET_RATE_GATE; 69 70 if (clk_register(clk)) { 71 clk_free(clk); 72 return NULL; 73 } 74 75 return clk; 76 } 77