]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/clk/uniphier/clk-uniphier-core.c
clk: convert API to match reset/mailbox style
[people/ms/u-boot.git] / drivers / clk / uniphier / clk-uniphier-core.c
CommitLineData
48264d9b
MY
1/*
2 * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.h>
8#include <mapmem.h>
9#include <linux/bitops.h>
10#include <linux/io.h>
45a3b1fd 11#include <linux/sizes.h>
135aa950 12#include <clk-uclass.h>
48264d9b
MY
13#include <dm/device.h>
14
15#include "clk-uniphier.h"
16
135aa950 17static int uniphier_clk_enable(struct clk *clk)
48264d9b 18{
135aa950 19 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
48264d9b
MY
20 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++) {
135aa950 27 if (gate[i].index != clk->id)
48264d9b
MY
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
135aa950 44static ulong uniphier_clk_get_rate(struct clk *clk)
48264d9b 45{
135aa950 46 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
48264d9b
MY
47 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++) {
135aa950 55 if (rdata[i].index != clk->id)
48264d9b
MY
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
135aa950 78static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate)
48264d9b 79{
135aa950 80 struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
48264d9b
MY
81 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++) {
135aa950 90 if (rdata[i].index != clk->id)
48264d9b
MY
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++) {
135aa950 108 if (rdata[i].index != clk->id || rdata[i].rate != best_rate)
48264d9b
MY
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
125const struct clk_ops uniphier_clk_ops = {
126 .enable = uniphier_clk_enable,
135aa950
SW
127 .get_rate = uniphier_clk_get_rate,
128 .set_rate = uniphier_clk_set_rate,
48264d9b
MY
129};
130
131int uniphier_clk_probe(struct udevice *dev)
132{
133 struct uniphier_clk_priv *priv = dev_get_priv(dev);
134 fdt_addr_t addr;
48264d9b 135
45a3b1fd 136 addr = dev_get_addr(dev);
48264d9b
MY
137 if (addr == FDT_ADDR_T_NONE)
138 return -EINVAL;
139
45a3b1fd 140 priv->base = map_sysmem(addr, SZ_4K);
48264d9b
MY
141 if (!priv->base)
142 return -ENOMEM;
143
144 priv->socdata = (void *)dev_get_driver_data(dev);
145
146 return 0;
147}
148
149int uniphier_clk_remove(struct udevice *dev)
150{
151 struct uniphier_clk_priv *priv = dev_get_priv(dev);
152
153 unmap_sysmem(priv->base);
154
155 return 0;
156}