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