1 /*
2  * Copyright (C) 2016 Atmel Corporation
3  *               Wenyou.Yang <wenyou.yang@atmel.com>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <clk-uclass.h>
10 #include <dm.h>
11 #include <linux/io.h>
12 #include <mach/at91_pmc.h>
13 #include "pmc.h"
14 
15 DECLARE_GLOBAL_DATA_PTR;
16 
17 #define GENERATED_SOURCE_MAX	6
18 #define GENERATED_MAX_DIV	255
19 
20 /**
21  * generated_clk_bind() - for the generated clock driver
22  * Recursively bind its children as clk devices.
23  *
24  * @return: 0 on success, or negative error code on failure
25  */
26 static int generated_clk_bind(struct udevice *dev)
27 {
28 	return at91_clk_sub_device_bind(dev, "generic-clk");
29 }
30 
31 static const struct udevice_id generated_clk_match[] = {
32 	{ .compatible = "atmel,sama5d2-clk-generated" },
33 	{}
34 };
35 
36 U_BOOT_DRIVER(generated_clk) = {
37 	.name = "generated-clk",
38 	.id = UCLASS_MISC,
39 	.of_match = generated_clk_match,
40 	.bind = generated_clk_bind,
41 };
42 
43 /*-------------------------------------------------------------*/
44 
45 struct generic_clk_priv {
46 	u32 num_parents;
47 };
48 
49 static ulong generic_clk_get_rate(struct clk *clk)
50 {
51 	struct pmc_platdata *plat = dev_get_platdata(clk->dev);
52 	struct at91_pmc *pmc = plat->reg_base;
53 	struct clk parent;
54 	ulong clk_rate;
55 	u32 tmp, gckdiv;
56 	u8 parent_id;
57 	int ret;
58 
59 	writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
60 	tmp = readl(&pmc->pcr);
61 	parent_id = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) &
62 		    AT91_PMC_PCR_GCKCSS_MASK;
63 	gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK;
64 
65 	ret = clk_get_by_index(dev_get_parent(clk->dev), parent_id, &parent);
66 	if (ret)
67 		return 0;
68 
69 	clk_rate = clk_get_rate(&parent) / (gckdiv + 1);
70 
71 	clk_free(&parent);
72 
73 	return clk_rate;
74 }
75 
76 static ulong generic_clk_set_rate(struct clk *clk, ulong rate)
77 {
78 	struct pmc_platdata *plat = dev_get_platdata(clk->dev);
79 	struct at91_pmc *pmc = plat->reg_base;
80 	struct generic_clk_priv *priv = dev_get_priv(clk->dev);
81 	struct clk parent, best_parent;
82 	ulong tmp_rate, best_rate = rate, parent_rate;
83 	int tmp_diff, best_diff = -1;
84 	u32 div, best_div = 0;
85 	u8 best_parent_id = 0;
86 	u8 i;
87 	u32 tmp;
88 	int ret;
89 
90 	for (i = 0; i < priv->num_parents; i++) {
91 		ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent);
92 		if (ret)
93 			return ret;
94 
95 		parent_rate = clk_get_rate(&parent);
96 		if (IS_ERR_VALUE(parent_rate))
97 			return parent_rate;
98 
99 		for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
100 			tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
101 			if (rate < tmp_rate)
102 				continue;
103 			tmp_diff = rate - tmp_rate;
104 
105 			if (best_diff < 0 || best_diff > tmp_diff) {
106 				best_rate = tmp_rate;
107 				best_diff = tmp_diff;
108 
109 				best_div = div - 1;
110 				best_parent = parent;
111 				best_parent_id = i;
112 			}
113 
114 			if (!best_diff || tmp_rate < rate)
115 				break;
116 		}
117 
118 		if (!best_diff)
119 			break;
120 	}
121 
122 	debug("GCK: best parent: %s, best_rate = %ld, best_div = %d\n",
123 	      best_parent.dev->name, best_rate, best_div);
124 
125 	ret = clk_enable(&best_parent);
126 	if (ret)
127 		return ret;
128 
129 	writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
130 	tmp = readl(&pmc->pcr);
131 	tmp &= ~(AT91_PMC_PCR_GCKDIV | AT91_PMC_PCR_GCKCSS);
132 	tmp |= AT91_PMC_PCR_GCKCSS_(best_parent_id) |
133 	       AT91_PMC_PCR_CMD_WRITE |
134 	       AT91_PMC_PCR_GCKDIV_(best_div) |
135 	       AT91_PMC_PCR_GCKEN;
136 	writel(tmp, &pmc->pcr);
137 
138 	while (!(readl(&pmc->sr) & AT91_PMC_GCKRDY))
139 		;
140 
141 	return 0;
142 }
143 
144 static struct clk_ops generic_clk_ops = {
145 	.of_xlate = at91_clk_of_xlate,
146 	.get_rate = generic_clk_get_rate,
147 	.set_rate = generic_clk_set_rate,
148 };
149 
150 static int generic_clk_ofdata_to_platdata(struct udevice *dev)
151 {
152 	struct generic_clk_priv *priv = dev_get_priv(dev);
153 	u32 cells[GENERATED_SOURCE_MAX];
154 	u32 num_parents;
155 
156 	num_parents = fdtdec_get_int_array_count(gd->fdt_blob,
157 			dev_of_offset(dev_get_parent(dev)), "clocks", cells,
158 			GENERATED_SOURCE_MAX);
159 
160 	if (!num_parents)
161 		return -1;
162 
163 	priv->num_parents = num_parents;
164 
165 	return 0;
166 }
167 
168 U_BOOT_DRIVER(generic_clk) = {
169 	.name = "generic-clk",
170 	.id = UCLASS_CLK,
171 	.probe = at91_clk_probe,
172 	.ofdata_to_platdata = generic_clk_ofdata_to_platdata,
173 	.priv_auto_alloc_size = sizeof(struct generic_clk_priv),
174 	.platdata_auto_alloc_size = sizeof(struct pmc_platdata),
175 	.ops = &generic_clk_ops,
176 };
177