]> git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/clk/uniphier/clk-uniphier-core.c
clk: uniphier: constify clock data arrays/structures
[people/ms/u-boot.git] / drivers / clk / uniphier / clk-uniphier-core.c
1 /*
2 * Copyright (C) 2016 Socionext Inc.
3 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8 #include <common.h>
9 #include <linux/bitops.h>
10 #include <linux/io.h>
11 #include <linux/sizes.h>
12 #include <clk-uclass.h>
13 #include <dm/device.h>
14
15 #include "clk-uniphier.h"
16
17 static int uniphier_clk_enable(struct clk *clk)
18 {
19 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
20 const struct uniphier_clk_gate_data *gate = priv->socdata->gate;
21 unsigned int nr_gate = priv->socdata->nr_gate;
22 void __iomem *reg;
23 u32 mask, data, tmp;
24 int i;
25
26 for (i = 0; i < nr_gate; i++) {
27 if (gate[i].index != clk->id)
28 continue;
29
30 reg = priv->base + gate[i].reg;
31 mask = gate[i].mask;
32 data = gate[i].data & mask;
33
34 tmp = readl(reg);
35 tmp &= ~mask;
36 tmp |= data & mask;
37 debug("%s: %p: %08x\n", __func__, reg, tmp);
38 writel(tmp, reg);
39 }
40
41 return 0;
42 }
43
44 static ulong uniphier_clk_get_rate(struct clk *clk)
45 {
46 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
47 const struct uniphier_clk_rate_data *rdata = priv->socdata->rate;
48 unsigned int nr_rdata = priv->socdata->nr_rate;
49 void __iomem *reg;
50 u32 mask, data;
51 ulong matched_rate = 0;
52 int i;
53
54 for (i = 0; i < nr_rdata; i++) {
55 if (rdata[i].index != clk->id)
56 continue;
57
58 if (rdata[i].reg == UNIPHIER_CLK_RATE_IS_FIXED)
59 return rdata[i].rate;
60
61 reg = priv->base + rdata[i].reg;
62 mask = rdata[i].mask;
63 data = rdata[i].data & mask;
64 if ((readl(reg) & mask) == data) {
65 if (matched_rate && rdata[i].rate != matched_rate) {
66 printf("failed to get clk rate for insane register values\n");
67 return -EINVAL;
68 }
69 matched_rate = rdata[i].rate;
70 }
71 }
72
73 debug("%s: rate = %lu\n", __func__, matched_rate);
74
75 return matched_rate;
76 }
77
78 static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate)
79 {
80 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
81 const struct uniphier_clk_rate_data *rdata = priv->socdata->rate;
82 unsigned int nr_rdata = priv->socdata->nr_rate;
83 void __iomem *reg;
84 u32 mask, data, tmp;
85 ulong best_rate = 0;
86 int i;
87
88 /* first, decide the best match rate */
89 for (i = 0; i < nr_rdata; i++) {
90 if (rdata[i].index != clk->id)
91 continue;
92
93 if (rdata[i].reg == UNIPHIER_CLK_RATE_IS_FIXED)
94 return 0;
95
96 if (rdata[i].rate > best_rate && rdata[i].rate <= rate)
97 best_rate = rdata[i].rate;
98 }
99
100 if (!best_rate)
101 return -ENODEV;
102
103 debug("%s: requested rate = %lu, set rate = %lu\n", __func__,
104 rate, best_rate);
105
106 /* second, really set registers */
107 for (i = 0; i < nr_rdata; i++) {
108 if (rdata[i].index != clk->id || rdata[i].rate != best_rate)
109 continue;
110
111 reg = priv->base + rdata[i].reg;
112 mask = rdata[i].mask;
113 data = rdata[i].data & mask;
114
115 tmp = readl(reg);
116 tmp &= ~mask;
117 tmp |= data;
118 debug("%s: %p: %08x\n", __func__, reg, tmp);
119 writel(tmp, reg);
120 }
121
122 return best_rate;
123 }
124
125 const struct clk_ops uniphier_clk_ops = {
126 .enable = uniphier_clk_enable,
127 .get_rate = uniphier_clk_get_rate,
128 .set_rate = uniphier_clk_set_rate,
129 };
130
131 int uniphier_clk_probe(struct udevice *dev)
132 {
133 struct uniphier_clk_priv *priv = dev_get_priv(dev);
134 fdt_addr_t addr;
135
136 addr = dev_get_addr(dev);
137 if (addr == FDT_ADDR_T_NONE)
138 return -EINVAL;
139
140 priv->base = devm_ioremap(dev, addr, SZ_4K);
141 if (!priv->base)
142 return -ENOMEM;
143
144 priv->socdata = (void *)dev_get_driver_data(dev);
145
146 return 0;
147 }