blob: 87d2069d89ce98de506588836ec09688ddf50dff [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Wenyou Yang8c772bd2016-07-20 17:55:12 +08002/*
3 * Copyright (C) 2016 Atmel Corporation
4 * Wenyou.Yang <wenyou.yang@atmel.com>
Wenyou Yang8c772bd2016-07-20 17:55:12 +08005 */
6
Simon Glass3ba929a2020-10-30 21:38:53 -06007#include <common.h>
Claudiu Beznea3f203a12020-09-07 17:46:39 +03008#include <asm/io.h>
Claudiu Beznea6fa98982020-09-07 17:46:51 +03009#include <clk-uclass.h>
Sean Anderson35c84642022-03-20 16:34:46 -040010#include <linux/clk-provider.h>
Claudiu Beznea6fa98982020-09-07 17:46:51 +030011#include "pmc.h"
12
13static int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
14{
15 if (args->args_count != 2) {
16 debug("AT91: clk: Invalid args_count: %d\n", args->args_count);
17 return -EINVAL;
18 }
19
20 clk->id = AT91_TO_CLK_ID(args->args[0], args->args[1]);
21
22 return 0;
23}
24
Claudiu Beznea6fa98982020-09-07 17:46:51 +030025const struct clk_ops at91_clk_ops = {
26 .of_xlate = at91_clk_of_xlate,
Sean Anderson35c84642022-03-20 16:34:46 -040027 .set_rate = ccf_clk_set_rate,
28 .get_rate = ccf_clk_get_rate,
29 .enable = ccf_clk_enable,
30 .disable = ccf_clk_disable,
Claudiu Beznea6fa98982020-09-07 17:46:51 +030031};
32
Claudiu Beznea8fdb4252020-09-07 17:46:38 +030033/**
34 * pmc_read() - read content at address base + off into val
35 *
36 * @base: base address
37 * @off: offset to read from
38 * @val: where the content of base + off is stored
39 *
40 * @return: void
41 */
42void pmc_read(void __iomem *base, unsigned int off, unsigned int *val)
43{
44 *val = readl(base + off);
45}
46
47/**
48 * pmc_write() - write content of val at address base + off
49 *
50 * @base: base address
51 * @off: offset to write to
52 * @val: content to be written at base + off
53 *
54 * @return: void
55 */
56void pmc_write(void __iomem *base, unsigned int off, unsigned int val)
57{
58 writel(val, base + off);
59}
60
61/**
62 * pmc_update_bits() - update a set of bits at address base + off
63 *
64 * @base: base address
65 * @off: offset to be updated
66 * @mask: mask of bits to be updated
67 * @bits: the new value to be updated
68 *
69 * @return: void
70 */
71void pmc_update_bits(void __iomem *base, unsigned int off,
72 unsigned int mask, unsigned int bits)
73{
74 unsigned int tmp;
75
76 tmp = readl(base + off);
77 tmp &= ~mask;
78 writel(tmp | (bits & mask), base + off);
79}
80
81/**
82 * at91_clk_mux_val_to_index() - get parent index in mux table
83 *
84 * @table: clock mux table
85 * @num_parents: clock number of parents
86 * @val: clock id who's mux index should be retrieved
87 *
88 * @return: clock index in mux table or a negative error number in case of
89 * failure
90 */
91int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val)
92{
93 int i;
94
95 if (!table || !num_parents)
96 return -EINVAL;
97
98 for (i = 0; i < num_parents; i++) {
99 if (table[i] == val)
100 return i;
101 }
102
103 return -EINVAL;
104}
105
106/**
107 * at91_clk_mux_index_to_val() - get parent ID corresponding to an entry in
108 * clock's mux table
109 *
110 * @table: clock's mux table
111 * @num_parents: clock's number of parents
112 * @index: index in mux table which clock's ID should be retrieved
113 *
114 * @return: clock ID or a negative error number in case of failure
115 */
116int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index)
117{
118 if (!table || !num_parents || index < 0 || index > num_parents)
119 return -EINVAL;
120
121 return table[index];
122}
Claudiu Bezneac32688f2023-03-08 16:39:52 +0200123
124int at91_clk_setup(const struct pmc_clk_setup *setup, int size)
125{
126 struct clk *c, *parent;
127 int i, ret;
128
129 if (!size)
130 return 0;
131
132 if (!setup)
133 return -EINVAL;
134
135 for (i = 0; i < size; i++) {
136 ret = clk_get_by_id(setup[i].cid, &c);
137 if (ret)
138 return ret;
139
140 if (setup[i].pid) {
141 ret = clk_get_by_id(setup[i].pid, &parent);
142 if (ret)
143 return ret;
144
145 ret = clk_set_parent(c, parent);
146 if (ret)
147 return ret;
148
149 if (setup[i].prate) {
150 ret = clk_set_rate(parent, setup[i].prate);
151 if (ret < 0)
152 return ret;
153 }
154 }
155
156 if (setup[i].rate) {
157 ret = clk_set_rate(c, setup[i].rate);
158 if (ret < 0)
159 return ret;
160 }
161 }
162
163 return 0;
164}