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
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
25const 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 */
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}
123
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}
165