Prepare v2023.10
[platform/kernel/u-boot.git] / drivers / clk / at91 / pmc.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Atmel Corporation
4  *               Wenyou.Yang <wenyou.yang@atmel.com>
5  */
6
7 #include <common.h>
8 #include <asm/io.h>
9 #include <clk-uclass.h>
10 #include <linux/clk-provider.h>
11 #include "pmc.h"
12
13 static 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
25 const struct clk_ops at91_clk_ops = {
26         .of_xlate       = at91_clk_of_xlate,
27         .set_rate       = ccf_clk_set_rate,
28         .get_rate       = ccf_clk_get_rate,
29         .enable         = ccf_clk_enable,
30         .disable        = ccf_clk_disable,
31 };
32
33 /**
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  */
42 void 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  */
56 void 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  */
71 void 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  */
91 int 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  */
116 int 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 }
123
124 int 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 }